// Copyright 2006 Nokia Corporation.
//
// THIS SOURCE CODE IS PROVIDED 'AS IS', WITH NO WARRANTIES WHATSOEVER,
// EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, FITNESS
// FOR ANY PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE
// OR TRADE PRACTICE, RELATING TO THE SOURCE CODE OR ANY WARRANTY OTHERWISE
// ARISING OUT OF ANY PROPOSAL, SPECIFICATION, OR SAMPLE AND WITH NO
// OBLIGATION OF NOKIA TO PROVIDE THE LICENSEE WITH ANY MAINTENANCE OR
// SUPPORT. FURTHERMORE, NOKIA MAKES NO WARRANTY THAT EXERCISE OF THE
// RIGHTS GRANTED HEREUNDER DOES NOT INFRINGE OR MAY NOT CAUSE INFRINGEMENT
// OF ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OWNED OR CONTROLLED
// BY THIRD PARTIES
//
// Furthermore, information provided in this source code is preliminary,
// and may be changed substantially prior to final release. Nokia Corporation
// retains the right to make changes to this source code at
// any time, without notice. This source code is provided for informational
// purposes only.
//
// Nokia and Nokia Connecting People are registered trademarks of Nokia
// Corporation.
// Java and all Java-based marks are trademarks or registered trademarks of
// Sun Microsystems, Inc.
// Other product and company names mentioned herein may be trademarks or
// trade names of their respective owners.
//
// A non-exclusive, non-transferable, worldwide, limited license is hereby
// granted to the Licensee to download, print, reproduce and modify the
// source code. The licensee has the right to market, sell, distribute and
// make available the source code in original or modified form only when
// incorporated into the programs developed by the Licensee. No other
// license, express or implied, by estoppel or otherwise, to any other
// intellectual property rights is granted herein.
package bcexchanger;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.pim.Contact;
import javax.microedition.pim.ContactList;
import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMItem;

/**
 * 
 * This class provides an abstraction of the address book to
 * application. It implements the access to the phone address book and
 * provides information in the form the application needs
 */
public class AddressBook {

  /**
   * This methods get all names from the address book and
   * corresponding uids.
   * <p>
   * This method retrieves full names from the address book and
   * corresponding uinque identifiers (uids)
   * 
   * @return two vectors: first is vector of names, second is the
   *         vector of corresponding UIDs
   * @exception Exception -
   *              in case any errors occur while working with address
   *              book
   */
  static public Vector[] getNamesUIDLists() throws Exception {
	  Vector[] namesUIDs = new Vector[2];
    namesUIDs[0] = new Vector();
    namesUIDs[1] = new Vector();
  
    // get the name of the address book
    PIM pim = PIM.getInstance();
    String listNames[] = pim.listPIMLists(PIM.CONTACT_LIST);
    if (listNames.length == 0) {
      throw new RuntimeException("No available Contact lists");
    }

    // opent the address book
    ContactList contactList = (ContactList) pim.openPIMList(
        PIM.CONTACT_LIST, PIM.READ_ONLY, listNames[0]);

    // veryfy the that the required list are supported
    if (!contactList.isSupportedField(Contact.UID)) {
      throw new RuntimeException(
          "Required field (UID) is not supported by the address book");
    }
    
    // list of preferd order of the name fields
    Vector fieldOrder = new Vector();
    fieldOrder.addElement(new Integer(Contact.FORMATTED_NAME)); // For Series40
    fieldOrder.addElement(new Integer(Contact.NAME_FAMILY));
    fieldOrder.addElement(new Integer(Contact.NAME_GIVEN));
    fieldOrder.addElement(new Integer(Contact.NAME)); // fix
    
    Vector supportedFieldOrder = new Vector();
    // create the supported list
    for(int i=0; i < fieldOrder.size(); i++) {

    	Integer field = (Integer) fieldOrder.elementAt(i);
    	if(contactList.isSupportedField(field.intValue())) {
    		supportedFieldOrder.addElement(field);
    	}
    }

    // in case none of the names is supported
    if(supportedFieldOrder.size() == 0) {
        throw new RuntimeException(
        "Required name field is not supported by the address book");
    }
    
    // get the list of contacts and uids
    Enumeration e = contactList.items();
    while (e.hasMoreElements()) {      
    	Contact contact = (Contact) e.nextElement();
      try {      
      	
      	// try to obtain any supported name
      	String name = null;
      	Enumeration e2 = supportedFieldOrder.elements();
      	while(e2.hasMoreElements()) {
      	  try {
      	  	int field = ((Integer) e2.nextElement()).intValue();

      	  	if (field == Contact.NAME)
      	  	{
      	  		String[] nameArray = contact.getStringArray(field,0);
      	  		if (nameArray != null) name = nameArray[0];
      	  	}
            else
            {
          	  	name = contact.getString(field, 0);
            }

      	  	if(name != null && name != "") {
      	  		break;
      	  	} else {
      	  		name = null;
      	  	}
      	  } catch (Exception exception) {
      	  	name = null;
      	  }
      	}
        
      	// this contact does not have a suitable name, continue with the next
      	if(name == null) {
      		continue;
      	}
        String uid = contact.getString(Contact.UID, 0);
  
        namesUIDs[0].addElement(name);
        namesUIDs[1].addElement(uid);
      } catch (IndexOutOfBoundsException ex) {
        // Ignore, this is a malformed contact and we'll omit it
      }
    }
    
    return namesUIDs;
  }
  
  
 
  /**
   * Get vCard of the address book entry with the particular uid
   * <p>
   * Longer description
   * 
   * @param uid -
   *          unique identifier of the requested address book entry
   * @return byte array which contains a vCard
   * @exception Exception -
   *              in case any error occur
   */
  static public byte[] getVCard(String uid) throws Exception {
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    // create a search pattern (based on uid)
    ContactList contactList = (ContactList) PIM.getInstance()
        .openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY);
    Contact searchPattern = contactList.createContact();
    searchPattern.addString(Contact.UID, PIMItem.ATTR_NONE, uid);

    Enumeration e = contactList.items(searchPattern);

    // get the first found contact
    if (e.hasMoreElements()) 
    {
      Contact contact = (Contact) e.nextElement();
      PIM.getInstance().toSerialFormat(contact, os, "UTF-8",
          "VCARD/2.1");
    } else 
    {
      throw new RuntimeException("No contacts found");
    }

    return os.toByteArray();
  }

  /**
   * Saves a vCard to the address book
   * <p>
   * Creates a new entry based on the infromation from the vCard in
   * the phones address book
   * 
   * @param vCard -
   *          byte array which contains a vCard
   * @exception Exception -
   *              in case any errors occur
   */
  static public void setVCard(byte[] vCard) throws Exception {
    ByteArrayInputStream in = new ByteArrayInputStream(vCard);

    // get address book entry from the input stream
    PIMItem[] items = PIM.getInstance().fromSerialFormat(in, "UTF-8");

    // takes the first one discards the others
    ContactList contactList = (ContactList) PIM.getInstance()
        .openPIMList(PIM.CONTACT_LIST, /* PIM.WRITE_ONLY */
        PIM.READ_WRITE);
    Contact newContact = contactList
        .importContact((Contact) items[0]);
    
    newContact.commit();
    
  }

}
